<template>
  <div class="vapp-helper">

    <!-- 左侧组件 -->
    <div class="component">

      <!-- 工具条 -->
      <div class="setting">
        <div class="env">
          <span>环境：</span>
          <el-select v-model="curEnv" size="default" class="env_select" @change="changeEnv">
            <el-option v-for="(n, i) in envInfo.envConf" :key="i" :label="i" :value="i"></el-option>
          </el-select>
        </div>
        <div class="size">
          <div>
            <span>宽度：</span>
            <Range v-model:value="layoutSize.width" :min="10" :max="2200" />
          </div>
          <div>
            <span>高度：</span>
            <Range v-model:value="layoutSize.height" :min="10" :max="2200" />
          </div>
        </div>
        <div class="new_comp">
          <el-button type="primary" icon="el-icon-plus" size="default" @click="addComp()" link>添加组件</el-button>
        </div>
      </div>

      <!-- 组件预览 -->
      <div class="inner preview">
        <div class="need_rename">
          <div v-if="vappConf.xvueNameSpace === 'components-demo'">
            注意，正式发布不可使用components-demo命名空间名，请修改AssetPack\vapp-meta-data.json和AssetPack\web\web-components\components.json下的xvueNameSpace属性值
          </div>
          <div>注意，本地模拟调试工具终究不是正式环境，一切调试效果以最终发包上环境后为准，另外请不要过于频繁切换组件，避免偶现本地模拟调试工具的缺陷</div>
        </div>
        <div v-for="item in compList" :key="item.id" :name="item.compName" class="comp-item" :style="{
          padding: '15px',
        }" @click="setCurComponent(item)">
          <div class="comp_toolbar">
            <div class="select-components">
              <el-select v-model="item.compName" size="default" style="width: 240px" filterable @change="initComp(item)">
                <el-option v-for="item in allCompList" :key="item.compName" :label="`${$demoi18n(item.cnName)} (${item.enName})`"
                  :value="item.compName"></el-option>
              </el-select>
            </div>
            <div class="size">
              <div>
                <span>宽度：</span>
                <Range v-model:value="item.width" :min="10" :max="2200" />
              </div>
              <div>
                <span>高度：</span>
                <Range v-model:value="item.height" :min="10" :max="2200" />
              </div>
            </div>
            <el-icon>
              <CircleCheck title="销毁/重建组件，用于检测有没有内存溢出" :class="{ on: item.isShow }" @click="toggleComp(item)" />
            </el-icon>
            <el-icon :class="{ on: item.isShow }" @click="deleteComp(item)">
              <Delete />
            </el-icon>
          </div>
          <div class="xVue-grid-item" :style="getCompStyle(item)">
            <component :is="getComp(item.compName)" v-if="item.compName && item.isShow"
              :ref="el => setRefMap(el, item.id)" class="comp" :w="item.width" :h="item.height"
              :widgetInstanceId="`${item.compName}_${item.id}`" />
          </div>
        </div>
      </div>
    </div>

    <!-- 右侧配置面板 -->
    <div class="config">
      <div v-for="item in compList" :key="`${item.id}_panel`" :name="item.compName" class="panel_item">
        <component :is="getCompPanel(item.compName)" v-if="item.config" v-show="item.id === curComp.id"
          :ref="`${item.id}_panel`" :config="item.config" :orgConfig="item.orgConfig" :widgetInstanceId="item.id" />
      </div>
    </div>
  </div>
</template>
<script>
import { nextTick, defineAsyncComponent } from 'vue';
import Range from '@/components/common/range/range.vue'
import login from './utils/login.js'
import envInfo from './config/envInfo';
import vappConf from '@/../AssetPack/vapp-meta-data.json'
import info from '../AssetPack/web/web-components/components.json'
const configModules = import.meta.glob(`@/components/*/config/config.js`)

function getRegisteredComponentsList() {
  const list = info.widgets.map(n => {
    let enName = n.name.replace(info.namePrefix, '')
    enName = enName.replace(/_/g, '-')
    return {
      compName: enName,
      cnName: n.displayName,
      enName,
    }
  })
  return list
}

function clone(obj) {
  return JSON.parse(JSON.stringify(obj));
}

// 新建组件池，从组件池拿组件，避免使用时动态生成
function useCompPool(name, defineFunc) {
  const compPoll = new Map()
  function getCompFormPool(key) {
    const uniKey = `${name}_${key}`
    if (compPoll.has(uniKey)) {
      return compPoll.get(uniKey)
    }
    compPoll.set(uniKey, defineAsyncComponent(() => defineFunc(key)));
    return compPoll.get(uniKey)
  }
  return { getCompFormPool }
}
const { getCompFormPool: getComp } = useCompPool('component', key => import(`../src/components/${key}/index.vue`));
const { getCompFormPool: getCompPanel } = useCompPool('config', key => import(`../src/components/${key}/config/config-panel.vue`));

const dfCompItem = {
  id: Date.now(),
  compName: '',
  cnName: '',
  enName: '',
  isShow: true,
  width: 1000, // 宽度不能设为0，否则echarts图表类组件会因为获取不到dom节点而报错
  height: 500,
  config: null,
  orgConfig: null,
}
const allCompList = getRegisteredComponentsList();
const compList = [JSON.parse(JSON.stringify(dfCompItem))];
const curEnv = envInfo.env;

export default {
  components: { Range },
  data() {
    return {
      vappConf,
      envInfo,
      curEnv,
      allCompList,
      compList,
      curComp: {},
      refMap: {},
      layoutSize: {
        width: 2200,
        height: 500,
      },
    };
  },
  watch: {
    layoutSize: {
      handler(size) {
        this.compList.forEach(n => {
          n.width = size.width
          n.height = size.height
        })
      },
      deep: true,
    }
  },
  created() {
    this.initEnv();
  },
  mounted() {
    window.saveVmConfig = this.saveVmConfig;
  },
  methods: {
    initEnv() {
      const { env } = login.getEnvInfo()
      if (!env) {
        login.setEnv(curEnv)
      }
    },
    saveVmConfig(config) {
      this.curComp.config = clone(config);
      const compVm = this.refMap[this.curComp.id];
      compVm.config = clone(config);
      compVm.loadWidget(undefined);
      this.$message({
        message: '保存成功',
        type: 'success',
      });
    },
    addComp() {
      const comp = clone(dfCompItem);
      comp.id = Date.now();
      this.compList.push(comp);
    },
    deleteComp(comp) {
      const index = compList.indexOf(comp)
      this.compList.splice(index, 1)
    },
    initComp(comp) {
      setTimeout(() => {
        this.curComp = comp
        // 获取组件对应config
        configModules[`/src/components/${comp.compName}/config/config.js`]().then(mod => {
          const _config = mod.default
          comp.config = clone(_config)
          comp.orgConfig = clone(_config)
          const compVm = this.refMap[comp.id]
          if (!compVm) {
            return
          }
          compVm.config = clone(_config)
          // compVm.loadWidget(undefined) // 调用的是前一个组件的loadWidget，应该注释掉，然后要在每个组件的mounted里判断如果是本地就执行自身的loadWidget;
        })
      }, 10)
    },
    setRefMap(el, id) {
      if (el) {
        this.refMap[id] = el;
      }
    },
    toggleComp(comp) {
      comp.isShow = !comp.isShow
      if (comp.isShow) {
        nextTick(() => {
          this.refMap[comp.id].loadWidget(undefined)
        })
      }
    },
    getCompStyle(comp) {
      const style = {width: '100%', height: '100%'};
      const { width, height } = comp;
      if (width) {
        style.width = `${width}px`
      }
      style.height = `${height}px`
      return style
    },
    setCurComponent(comp) {
      this.curComp = comp;
    },
    getComp,
    getCompPanel,
    changeEnv(env) {
      login.setEnv(env)
    },
  },
}
</script>
<style lang="less" scoped>
.vapp-helper {
  width: 100%;
  height: 100vh;
  font-size: 13px;
  display: flex;

  .component {
    padding: 0 10px 0 10px;
    height: 100%;
    flex-grow: 1;
    display: flex;
    flex-direction: column;

    .setting {
      flex-grow: 0;
      display: flex;
      justify-content: flex-end;
      align-items: center;

      >div {
        display: flex;
        align-items: center;
        margin-right: 15px;
        flex-direction: column;
        justify-content: center;

        &.env {
          flex-direction: row;
        }
      }



      .all-components {
        margin-right: 5px;
        width: 180px;
      }

      .env_select {
        width: 130px;
      }

      :deep(.range-box) {
        .el-slider {
          width: 80px;
        }
      }
    }

    .size {
      flex-wrap: wrap;

      div {
        display: flex;
        align-items: center;
        height: 26px;

        span {
          width: 52px;
        }
      }
    }

    .preview {
      margin-top: 10px;
      overflow-y: auto;
      height: 100px;
      flex: 1;

      .need_rename {
        color: red;
      }

      .comp-item {
        border: 1px solid #ccc;
        box-sizing: border-box;
        position: relative;
        background: linear-gradient(#fff 0%, #e2f0ff 50%, #d5eaff 100%);
        display: flex;
        flex-direction: column;
        margin-bottom: 20px;

        .comp_toolbar {
          display: flex;
          justify-content: flex-end;
          align-items: center;
          flex-grow: 0;
          flex-shrink: 0;
          background-color: #393939;
          padding: 5px 10px;

          .select-components {
            margin-right: 10px;
          }

          .size {
            display: flex;
            align-items: center;

            >div {
              margin-right: 10px;
              display: flex;
              align-items: center;
              color: #607d8b;
            }
          }

          i {
            margin-left: 10px;
            color: #fff;
            font-size: 18px;
            cursor: pointer;

            &.on {
              color: #8bc34a;
            }
          }
        }

        .xVue-grid-item {
          background-color: #fff;
          border: 1px solid #607d8b;
        }
      }
    }
  }

  .config {
    width: 300px;
    border-left: 1px solid #ccc;
    position: relative;
    flex-shrink: 0;

    .component_box {
      display: flex;
      flex-direction: column;
    }
  }
}

:deep(.token_table) {
  width: 100%;
}</style>
